package br.com.fogas.medicao.business;

import java.sql.SQLException;
import java.util.Date;

import android.content.Intent;
import android.util.Log;
import br.com.fogas.database.entidade.NotaControle;
import br.com.fogas.medicao.R;
import br.com.fogas.medicao.activity.LoginActivity;
import br.com.fogas.medicao.activity.MainActivity;
import br.com.fogas.medicao.activity.SincronizacaoActivity;
import br.com.fogas.medicao.application.ApplicationFogas;
import br.com.fogas.medicao.application.Constants;
import br.com.fogas.medicao.utils.MedicaoUtils;
import br.com.fogas.modelo.Configuracao;
import br.com.fogas.notafiscal.enums.MaterialEnum;
import br.com.fogas.utils.FogasUtility;
import br.com.fogas.utils.StringUtility;
import br.com.fogas.utils.exception.ParseXmlException;
import br.com.fogas.utils.exception.VersaoSistemaException;
import br.com.fogas.webservice.exception.ERaiseWebServiceException;
import br.com.fogas.webservice.exception.RespostaWebServiceException;
import br.com.fogas.webservice.exception.SemConexaoInternetException;
import br.com.fogas.webservice.exception.ServidorForaException;
import br.com.fogas.webservice.exception.TempoEsperaRespostaException;
import br.com.fogas.webservice.exception.WebServiceException;
import br.com.fogas.webservice.parser.cliente.ClienteRequest;
import br.com.fogas.webservice.parser.cliente.ClienteResponse;
import br.com.fogas.webservice.parser.condicoes.CondicoesRequest;
import br.com.fogas.webservice.parser.condicoes.CondicoesResponse;
import br.com.fogas.webservice.parser.config.ConfigRequest;
import br.com.fogas.webservice.parser.config.ConfigResponse;
import br.com.fogas.webservice.parser.material.MaterialRequest;
import br.com.fogas.webservice.parser.material.MaterialResponse;
import br.com.fogas.webservice.parser.material.MaterialResponseItem;
import br.com.fogas.webservice.parser.sincronizacao_ok.SincronizacaoOkRequest;

public class SincronizacaoBusiness {
	
	public static final String LOG_TAG = "SINCRONIZACAO"; 
	
	private SincronizacaoActivity activity;

	public SincronizacaoBusiness(SincronizacaoActivity activity) {
		this.activity = activity;
	}
	
	public void iniciar() {
		try {
			Configuracao configuracao = validaToken();
			verificaVersao(configuracao);
			gravaCondicoes(configuracao);
			gravaMateriais(configuracao);
			gravaNotaControle(configuracao);
			gravaClientes(configuracao);
			gravarConfiguracao(configuracao);
			sincronizacaoOK(configuracao);
			entrarApp();
		} catch (SemConexaoInternetException e) {
			String message = activity.getString(R.string.sinc_msg_sem_internet_exception);
			loginApp(message);
		} catch (ParseXmlException e) {
			loginApp(null);
		} catch (TempoEsperaRespostaException e) {
			String message = activity.getString(R.string.sinc_msg_tempo_espera_exception);
			loginApp(message);
		} catch (ServidorForaException e) {
			String message = activity.getString(R.string.sinc_msg_servidorfora_exception);
			loginApp(message);
		} catch (RespostaWebServiceException e) {
			String message = activity.getString(R.string.sinc_msg_respostawebservice_exception);
			loginApp(message);
		} catch (WebServiceException e) {
			loginApp(null);
		} catch (ERaiseWebServiceException e) {
			String message = StringUtility.isNotEmpty(e.getMessage()) ? e.getMessage() : null;
			loginApp(message);
		} catch (VersaoSistemaException e) {
			loginApp(e.getMessage());
		} catch (SQLException e) {
			loginApp(null);
		}
	}

	private void roolbackDatabase() {
		activity.getDatabase().getHelper().dropAndCreateTables();
	}
	
	private void atualizarProgresso(int progresso, String message) {
		activity.atualizarProgressBar(progresso+"%", message, progresso);
	}
	
	private void gravarConfiguracao(Configuracao configuracao) throws SQLException {
		activity.getDatabase().getConfig().sincronizar(configuracao);
		ApplicationFogas.getInstance().setConfiguracao();
	}
	
	private void sincronizacaoOK(Configuracao configuracao)
			throws SemConexaoInternetException, ParseXmlException,
			TempoEsperaRespostaException, ServidorForaException,
			RespostaWebServiceException, WebServiceException,
			ERaiseWebServiceException {
		
		SincronizacaoOkRequest request = new SincronizacaoOkRequest();
		request.setImei(configuracao.getAppDados().getImei()); 
		request.setToken(configuracao.getAppDados().getToken());
		request.setPlano(configuracao.getAppDados().getPlano());
		activity.getWebservice().sincronizacaoOK(request).getResponse();
	}
	
	private void entrarApp() {
		Intent intent = new Intent(activity, MainActivity.class);
		activity.startActivity(intent);
		activity.finish();
	}
	
	private void loginApp(String message) {
		roolbackDatabase();
		
		if(StringUtility.isEmpty(message)) {
			message = activity.getString(R.string.msg_exception_ws_config_runtimeexception);
		}
		
		Intent intent = new Intent(activity, LoginActivity.class);
		intent.putExtra(Constants.ERROR_SINCRONIZACAO, message);
		activity.startActivity(intent);
		activity.finish();
	}
	
	private Configuracao validaToken() throws SemConexaoInternetException,
			ParseXmlException, TempoEsperaRespostaException,
			ServidorForaException, RespostaWebServiceException,
			WebServiceException, ERaiseWebServiceException {
		try {
			atualizarProgresso(0, "Validando token...");
			
			ConfigRequest request = new ConfigRequest();
			request.setToken(activity.getToken());
			request.setImei(activity.getImei());
			
			ConfigResponse response = activity.getWebservice().config(request).getResponse();
			Configuracao configuracao = new Configuracao(response);
			configuracao.getAppDados().setToken(activity.getToken());
			configuracao.getAppDados().setPlano(getNumPlano(activity.getToken()));
			configuracao.getAppDados().setAutorizar_nfe_online(true);
			configuracao.getAppDados().setTentativas_leitura_qrcode(2);
			configuracao.getAppDados().setTempo_espera_aut_nfe(60 * 4);//4 min
			configuracao.getAppDados().setTempo_processamento_sync(10);//10 segundos 
			configuracao.getAppDados().setSenha_adm("adm@123");
			return configuracao;
		} catch (Exception e) {
			Log.e(LOG_TAG, "erro ocorrido no metodo validaToken() causa: "+e.getMessage());
			
			if(e instanceof ERaiseWebServiceException) {
				throw new ERaiseWebServiceException(messagemErroValidaToken(e.getMessage()));
			} else {
				throw e;
			}
		}
	}
	
	private String getNumPlano(String token) {
		return token + FogasUtility.data.getStringByDateAndFormat(new Date(), "ddMMyy");
	}

	private String messagemErroValidaToken(String exception) {
		exception = StringUtility.stripAccents(exception);
		exception = StringUtility.upperCase(exception);
		if(StringUtility.equals(exception, "TOKEN INFORMADO NAO E VALIDO")) {
			return activity.getString(R.string.msg_exception_ws_config_tokeninvalido);
		} else if(StringUtility.equals(exception, "CONTROLE DE NOTA NAO ENCONTRADO")) {
			return activity.getString(R.string.msg_exception_ws_config_tokencontrolenota);
		} else if(StringUtility.equals(exception, "O TOKEN INFORMADO NAO ESTA CONFIGURADO PARA ESSE IMEI")) {
			return activity.getString(R.string.msg_exception_ws_config_tokenoutrodispositivo);
		} else if(StringUtility.contains(exception, StringUtility.upperCase("PENDENTE DE FINALIZACAO"))) {
			return messageSincPendente(exception);
		} else {
			return activity.getString(R.string.msg_exception_ws_config_tokencontrolenota);
		}
	}
	
	private String messageSincPendente(String message) {
		//String message = "Sincronizacao do dia 19 . 02 . 15 as 08 : 19 pendente de finalizacao";
		message = StringUtility.upperCase(message);
		String between1 = StringUtility.upperCase("SINCRONIZACAO DO DIA");
		String between2 = StringUtility.upperCase("PENDENTE DE FINALIZACAO");
		
		String subString = StringUtility.substringBetween(message, between1, between2);
		String dt = "";
		for(char c: subString.toCharArray()) {
			String str = String.valueOf(c);
			if(!StringUtility.equals(str, " ")) {
				dt += str;
			}
		}
		String dia = StringUtility.substring(dt, 0, 6)+"20"+StringUtility.substring(dt, 6, 8);
		dia = StringUtility.replace(dia, ".", "/");
		String hora = StringUtility.substring(dt, 10, 15);
		String data = dia +" "+ hora;
		
		message = activity.getString(R.string.message_sinc_pendente_fin);
		message = StringUtility.replace(message, "#DATA", data);
		return StringUtility.trim(message);
	}
	
	private void verificaVersao(Configuracao configuracao) throws VersaoSistemaException {
		try {
			atualizarProgresso(20, "Validando versão app...");
			MedicaoUtils.validaVersaoApp(configuracao.getAppDados().getVersao());
		} catch (VersaoSistemaException e) {
			Log.e(LOG_TAG, "erro ocorrido no metodo verificaVersao() causa: "+ e.getMessage());
			
			String message = "";
			
			if(StringUtility.equals(e.getMessage(), "VERSAO_DESATUALIZADA")) {
				message = activity.getString(R.string.versao_desatualizada);
			} else if(StringUtility.equals(e.getMessage(), "VERSAO_FORA_PADRAO_1.0.0")) {
				message = activity.getString(R.string.versao_fora_padrao);
			} else if(StringUtility.equals(e.getMessage(), "VERSAO_SAP_VAZIA")) {
				message = activity.getString(R.string.versao_inativa_sap);
			}
			
			throw new VersaoSistemaException(message);
		}
	}
	
	private void gravaCondicoes(Configuracao configuracao)
			throws SemConexaoInternetException, ParseXmlException,
			TempoEsperaRespostaException, ServidorForaException,
			RespostaWebServiceException, WebServiceException,
			ERaiseWebServiceException, SQLException {
		try {
			CondicoesRequest request = new CondicoesRequest();
			request.setI_vkorg(configuracao.getAppDados().getOrgVendas());
			request.setI_werks(configuracao.getAppDados().getCentroVendas());
			
			atualizarProgresso(25, "Sincronizando...");
			CondicoesResponse response = activity.getWebservice().condicoes(request).getResponse();
			atualizarProgresso(35, "Gravando...");
			activity.getDatabase().getCondicaoPagamento().sincronizar(response.getT_COND_PGTO().getItems());
			activity.getDatabase().getA903().sincronizar(response.getT_A903().getItems());
			activity.getDatabase().getA942().sincronizar(response.getT_A942().getItems());
			activity.getDatabase().getA951().sincronizar(response.getT_A951().getItems());
			activity.getDatabase().getA952().sincronizar(response.getT_A952().getItems());
			activity.getDatabase().getA957().sincronizar(response.getT_A957().getItems());
			activity.getDatabase().getA962().sincronizar(response.getT_A962().getItems());
			activity.getDatabase().getA963().sincronizar(response.getT_A963().getItems());
			activity.getDatabase().getA965().sincronizar(response.getT_A965().getItems());
			activity.getDatabase().getA966().sincronizar(response.getT_A966().getItems());
			activity.getDatabase().getA970().sincronizar(response.getT_A970().getItems());
			atualizarProgresso(45, "Gravando...");
			activity.getDatabase().getA971().sincronizar(response.getT_A971().getItems());
			activity.getDatabase().getA972().sincronizar(response.getT_A972().getItems());
			activity.getDatabase().getA973().sincronizar(response.getT_A973().getItems());
			activity.getDatabase().getA975().sincronizar(response.getT_A975().getItems());
			activity.getDatabase().getA976().sincronizar(response.getT_A976().getItems());
			activity.getDatabase().getA977().sincronizar(response.getT_A977().getItems());
			activity.getDatabase().getA979().sincronizar(response.getT_A979().getItems());
			activity.getDatabase().getA982().sincronizar(response.getT_A982().getItems());
			activity.getDatabase().getA983().sincronizar(response.getT_A983().getItems());
			activity.getDatabase().getA987().sincronizar(response.getT_A987().getItems());
		} catch (Exception e) {
			Log.e(LOG_TAG, "erro ocorrido no metodo gravaCondicoes() causa: "+ e.getMessage());
			throw e;
		}
	}
	
	private void gravaMateriais(Configuracao configuracao)
			throws SemConexaoInternetException, ParseXmlException,
			TempoEsperaRespostaException, ServidorForaException,
			RespostaWebServiceException, WebServiceException,
			ERaiseWebServiceException, SQLException {
		try {
			MaterialRequest request = new MaterialRequest();
			request.setMatnr(MaterialEnum.GLP.getCodigo());
			request.setWerks(configuracao.getAppDados().getCentroVendas());
			
			atualizarProgresso(50, "Sincronizando...");
			MaterialResponse response = activity.getWebservice().material(request).getResponse();
			if(!response.getMateriais().isEmpty()) {
				MaterialResponseItem material = response.getMateriais().get(0);
				material.setUnidade(MaterialEnum.GLP.getUnidade());
			}
			
			atualizarProgresso(55, "Gravando...");
			activity.getDatabase().getMaterial().sincronizar(response.getMateriais());
		} catch (Exception e) {
			Log.e(LOG_TAG, "erro ocorrido no metodo gravaMateriais() causa: "+e.getMessage());
			throw e;
		}
	}
	
	private void gravaNotaControle(Configuracao configuracao) throws SQLException {
		try {
			atualizarProgresso(60, "Sincronizando...");
			NotaControle nota = new NotaControle(configuracao.getAppDados().getUltimaNfEmitida(), 
					configuracao.getAppDados().getSerieNf());
			atualizarProgresso(65, "Gravando...");
			activity.getDatabase().getNotaControle().create(nota);
		} catch (SQLException e) {
			Log.e(LOG_TAG, "erro ocorrido no metodo gravaNotaControle() causa: "+e.getMessage());
			throw e;
		}
	}
	
	private void gravaClientes(Configuracao configuracao)
			throws SemConexaoInternetException, ParseXmlException,
			TempoEsperaRespostaException, ServidorForaException,
			RespostaWebServiceException, WebServiceException,
			ERaiseWebServiceException, SQLException {
		try {
			atualizarProgresso(70, "Sincronizando...");
			ClienteRequest request = new ClienteRequest();
			request.setI_vkorg(configuracao.getAppDados().getOrgVendas());
			ClienteResponse response = activity.getWebservice().cliente(request).getResponse();
			
			atualizarProgresso(75, "Gravando...");
			activity.getDatabase().getCanal().sincronizar(response.getCanal().getCanais());
			
			atualizarProgresso(80, "Gravando...");
			activity.getDatabase().getCliente().sincronizar(response.getCliente().getClientes());
			
			atualizarProgresso(85, "Gravando...");
			activity.getDatabase().getMedidor().sincronizar(response.getMedidor().getMedidores());
			
			atualizarProgresso(90, "Gravando...");
			activity.getDatabase().getMedidorHistorico().sincronizar(response.getMedidorHistorico().getMedidores());
		} catch (Exception e) {
			Log.e(LOG_TAG, "erro ocorrido no metodo gravaClientes() causa: "+ e.getMessage());
			throw e;
		}
	}
}